﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DDD;
using Xunit;

namespace DokiDokiTest {
    public class TestAnimationClip {
        [Fact]
        public void Test_New1 () {
            var clip = new AnimationClip ("Hello world");

            Assert.Equal (1.0f, clip.Speed);
            Assert.Equal (1.0f, clip.Weight);
            Assert.Equal (0, clip.ActiveIntervalStart);
            Assert.Equal (0, clip.ActiveIntervalEnd);
            Assert.Equal (0, clip.Duration);
            Assert.Equal (0, clip.TrackCount);
            Assert.Equal (0, clip.EventCount);
            Assert.Equal ("Hello world", clip.Name);
            Assert.Equal (true, clip.IsActive (-100));
            Assert.Equal (0, clip.LocalReferenceTime);
            Assert.Equal (0, clip.WorldReferenceTime);
        }


        [Fact]
        public void Test_GetLocalTime () {
            var clip = new AnimationClip ("Hello world");

            Assert.Equal (1.0f, clip.Speed);
            Assert.Equal (0, clip.LocalReferenceTime);
            Assert.Equal (0, clip.WorldReferenceTime);

            Assert.Equal (0, clip.GetLocalTime (0));
            Assert.Equal (100, clip.GetLocalTime (100));
            Assert.Equal (-100, clip.GetLocalTime (-100));
        }

        [Fact]
        public void Test_GetWorldTime () {
            var clip = new AnimationClip ("Hello world");

            Assert.Equal (1.0f, clip.Speed);
            Assert.Equal (0, clip.LocalReferenceTime);
            Assert.Equal (0, clip.WorldReferenceTime);

            Assert.Equal (0, clip.GetWorldTime (0));
            Assert.Equal (100, clip.GetWorldTime (100));
            Assert.Equal (-100, clip.GetWorldTime (-100));
        }

        /// <summary>
        /// 再生速度の変更のテスト
        /// </summary>
        /// <remarks>
        /// ワールドリファレンス時間をセットすると変更前後でアニメーションが連続する
        /// </remarks>
        [Fact]
        public void Test_SetSpeed () {
            var clip = new AnimationClip ("Hello world");
            clip.SetSpeed (0.5f, 100);

            Assert.Equal (0.5f, clip.Speed);
            Assert.Equal (100, clip.LocalReferenceTime, new FloatComparer (0.0001f));
            Assert.Equal (100, clip.WorldReferenceTime);

            Assert.Equal (50, clip.GetLocalTime (0));
            Assert.Equal (100, clip.GetLocalTime (100));
            Assert.Equal (150, clip.GetLocalTime (200));
        }

        /// <summary>
        /// アクティブ区間のテスト
        /// </summary>
        /// <remarks>
        /// start==endの時は全区間で有効
        /// </remarks>
        [Fact]
        public void Test_SetActiveInterval () {
            var clip = new AnimationClip ("Hello world");

            clip.SetActiveInterval (100, 200);

            Assert.Equal (true, clip.IsActive (150));
            Assert.Equal (false, clip.IsActive (300));

            clip.SetActiveInterval (100, 100);

            Assert.Equal (true, clip.IsActive (150));
            Assert.Equal (true, clip.IsActive (300));
        }

        /// <summary>
        /// 再生位置の変更のテスト
        /// </summary>
        [Fact]
        public void Test_SetPlaybackPosition () {
            var clip = new AnimationClip ("Hello world");

            Assert.Equal (100, clip.GetLocalTime (100));

            clip.SetPlaybackPosition (100, 200);

            Assert.Equal (200, clip.LocalReferenceTime);
            Assert.Equal (100, clip.WorldReferenceTime);
            Assert.Equal (200, clip.GetLocalTime (100));
        }

        [Fact]
        public void Test_AddTrack () {
            var clip = new AnimationClip ("Hello world");
            var kseq = new KeyframeSequence<float> (4, 3);
            var track1 = new AnimationTrack (kseq, "Some property1");
            var track2 = new AnimationTrack (kseq, "Some property2");

            clip.AddTrack (track1);
            clip.AddTrack (track2);

            Assert.Equal (2, clip.TrackCount);
            Assert.Equal (track1, clip.GetTrack (0));
            Assert.Equal (track2, clip.GetTrack (1));
        }

        [Fact]
        public void Test_RemoveTrack () {
            var clip = new AnimationClip ("Hello world");
            var kseq = new KeyframeSequence<float> (4, 3);
            var track1 = new AnimationTrack (kseq, "Some property1");
            var track2 = new AnimationTrack (kseq, "Some property2");

            clip.AddTrack (track1);
            clip.AddTrack (track2);

            clip.RemoveTrack (track1);
            clip.RemoveTrack (track2);

            Assert.Equal (0, clip.TrackCount);
        }

        [Fact]
        public void Test_AddEvent () {
            var clip = new AnimationClip ("Hello world");
            var handler = (AnimationEventHandler)delegate (DDD.Object obj, object args) { };

            clip.AddEvent (1.0f, "Erica Hartmann", handler, null);
            clip.AddEvent (2.0f, "Ursula Hartmann", handler, null);

            Assert.Equal (2, clip.EventCount);
            Assert.Equal (1.0f, clip.GetEvent ("Erica Hartmann").Time);
            Assert.Equal (2.0f, clip.GetEvent ("Ursula Hartmann").Time);
        }

        [Fact]
        public void Test_RemoveEvent () {
            var clip = new AnimationClip ("Hello world");
            var handler = (AnimationEventHandler)delegate (DDD.Object obj, object args) { };

            clip.AddEvent (1.0f, "Erica Hartmann", handler, null);
            clip.AddEvent (2.0f, "Ursula Hartmann", handler, null);

            clip.RemoveEvent ("Erica Hartmann");
            clip.RemoveEvent ("Ursula Hartmann");

            Assert.Equal (0, clip.EventCount);
        }

        [Fact]
        public void Test_SetWeight () {
            var clip = new AnimationClip ("Hello world");
            clip.SetWeight (2.0f);

            Assert.Equal (2.0f, clip.Weight);
        }

        [Fact]
        public void Test_TrackEnumerator () {
            var kseq = new KeyframeSequence<float> (4, 3);
            var track1 = new AnimationTrack (kseq, "Some property1");
            var track2 = new AnimationTrack (kseq, "Some property2");
            var clip = new AnimationClip ("Hello world");
            clip.AddTrack (track1);
            clip.AddTrack (track2);

            var sum = clip.Tracks.Sum (x => 1);

            Assert.Equal (2, sum);
        }

        [Fact]
        public void Test_EventEnumerator () {
            var clip = new AnimationClip ("Hello world");
            var handler = (AnimationEventHandler)delegate (DDD.Object obj, object args) { };
            clip.AddEvent (1.0f, "Erica Hartmann", handler, null);
            clip.AddEvent (2.0f, "Ursula Hartmann", handler, null);

            var sum = clip.Events.Sum (x => 1);

            Assert.Equal (2, sum);
        }

        [Fact]
        public void Test_Duration () {
            var kseq1 = new KeyframeSequence<float> (4, 3);
            var kseq2 = new KeyframeSequence<float> (4, 3);
            var kseq3 = new KeyframeSequence<float> (4, 3);
            kseq1.SetDuration (1);
            kseq2.SetDuration (2);
            kseq3.SetDuration (3);
            var track1 = new AnimationTrack (kseq1, "Some property1");
            var track2 = new AnimationTrack (kseq2, "Some property2");
            var track3 = new AnimationTrack (kseq3, "Some property3");

            var clip = new AnimationClip ("Hello world");
            clip.AddTrack (track1);
            clip.AddTrack (track2);
            clip.AddTrack (track3);

            Assert.Equal (3, clip.Duration);
        }

        [Fact]
        public void Test_References () {
            var kseq1 = new KeyframeSequence<float> (4, 3);
            var kseq2 = new KeyframeSequence<float> (4, 3);
            var kseq3 = new KeyframeSequence<float> (4, 3);
            var track1 = new AnimationTrack (kseq1, "Some property 1");
            var track2 = new AnimationTrack (kseq2, "Some property 2");
            var track3 = new AnimationTrack (kseq3, "Some property 3");

            var clip = new AnimationClip ("Some Animation Clip");
            clip.AddTrack (track1);
            clip.AddTrack (track2);
            clip.AddTrack (track3);

            var objs = clip.References;

            Assert.Equal (3, objs.Count ());
            Assert.Equal (true, objs.All (x => x != null));
        }

        [Fact]
        public void Test_Find () {
            var kseq1 = new KeyframeSequence<float> (4, 3);
            var kseq2 = new KeyframeSequence<float> (4, 3);
            var kseq3 = new KeyframeSequence<float> (4, 3);
            var track1 = new AnimationTrack (kseq1, "Some property 1");
            var track2 = new AnimationTrack (kseq2, "Some property 2");
            var track3 = new AnimationTrack (kseq3, "Some property 3");

            var clip = new AnimationClip ("Some Animation Clip");
            clip.AddTrack (track1);
            clip.AddTrack (track2);
            clip.AddTrack (track3);

            kseq1.UserID = 101;
            kseq2.UserID = 102;
            kseq3.UserID = 103;
            track1.UserID = 104;
            track2.UserID = 105;
            track3.UserID = 106;
            clip.UserID = 107;

            Assert.Equal (kseq1, clip.Find (101));
            Assert.Equal (kseq2, clip.Find (102));
            Assert.Equal (kseq3, clip.Find (103));
            Assert.Equal (track1, clip.Find (104));
            Assert.Equal (track2, clip.Find (105));
            Assert.Equal (track3, clip.Find (106));
            Assert.Equal (clip, clip.Find (107));
        }

    }
}
